home *** CD-ROM | disk | FTP | other *** search
- /*
- * SENDMSG: Utility to send messages for *.MSG or *.SQ? bases
- *
- * Created: 05/Dec/92
- * Updated: 07/Apr/96
- *
- * Written by Pete Kvitek of JV Dialogue 1st BBS (2:5020/6) +7-095-329-2192
- * Copyright (c) 1992-1996 by JV DIALOGUE. All rights reserved.
- *
- * History:
- *
- * 07/Apr/96 -- v1.02
- * Ported code to MSC 6.0a to compile for DOS and OS/2 1.xx
- * Updated code to use Scott's SQDEV200 instead of MSGAPI0
- * Implemented more robuts ^aMSGID time stamp generation
- * Changed ^aMSGID generation so that now it is not optional
- * Added ^aPID kludge generation
- *
- * 05/Feb/93 -- v1.01
- * Corrected 'grunged date' problem
- * Added optional ^aMSGID generation
- *
- * 05/Dec/92 -- v1.00
- * Originally written
- *
- */
-
- // COMPILATION NOTES:
- // The SendMsg code was compiled in LARGE memory model using
- // Borland's C++ and Microsoft C v6.00a, however newer
- // versions may serve as well -- at least I hope so...
-
- #ifdef __OS2__
- #define INCL_NOCOMMON
- #define INCL_NOPM
- #define INCL_DOSFILEMGR
- #define INCL_DOSMEMMGR
- #define INCL_DOSINFOSEG
- #define INCL_DOSPROCESS
- #include <os2.h>
- #define OS_2
- #endif
-
- #include <io.h>
- #include <dos.h>
- #include <time.h>
- #include <ctype.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <direct.h>
-
- // Remove the EXPENTRY definition since the Scott's API has one too.
- // Both appear to be identical except for the far call specification,
- // but since we're compiling in large model this is not a problem...
-
- #undef EXPENTRY
- #include "msgapi.h"
-
- /////////////////////////////////////////////////////////////////////////////
- // M o d u l e d e c l a r a t i o n s //
- /////////////////////////////////////////////////////////////////////////////
-
- // Some useful defines
-
- #define loop while (1) // Endless loop 'till break
- #define numbof(a) (sizeof(a)/sizeof(a[0])) // Number of elements
- #define lengof(s) (sizeof(s) - 1) // Length of the string
-
- #define TRUE 1
- #define FALSE 0
-
- #ifndef __OS2__
- #define BOOL int
- #define ULONG unsigned long
- #endif
-
- // Some compiler dependant stuff
-
- #if defined(__TURBOC__) || defined(__BORLANDC__)
- #define FN_MAXPATH MAXPATH
- #define FN_MAXDRIVE MAXDRIVE
- #define FN_MAXDIR MAXDIR
- #define FN_MAXFILE MAXFILE
- #define FN_MAXEXT MAXEXT
- #elif defined(__MSC__)
- #define FN_MAXPATH _MAX_PATH
- #define FN_MAXDRIVE _MAX_DRIVE
- #define FN_MAXDIR _MAX_DIR
- #define FN_MAXFILE _MAX_FNAME
- #define FN_MAXEXT _MAX_EXT
- #else
- #error Unknown complier
- #endif
-
- // Miscellaneous defines
-
- #define VERSION "1.02" // Revision level
-
- #ifndef __OS2__
- #define SMSG_NAME "SendMsg" // Utility name (dos)
- #else
- #define SMSG_NAME "SendMsg/2" // Utility name (os/2)
- #endif
-
- #define SMSG_PID "\x01""PID: "SMSG_NAME" v"VERSION // PID kludge
- #define SMSG_TEARLINE "\r--- "SMSG_NAME"\r" // Tear line
-
- #define MSGTEXT stdin // Message text input handle
- #define AUXTEXT stdout // Auxiliary text output handle
-
- #define ISOPTION(ch) ((ch)=='-'||(ch)=='/') // Command line option prefix
-
- // Program control flags in 'fsFlags'
-
- #define FL_SQUISHMAIL 0x0001 // Squish mail folder
-
- // Module variables
-
- static char achPath[FN_MAXPATH]; // Path to mail folder
- static unsigned fsFlags; // Control flags FL_
- static HAREA harea; // Mail folder handle
- static XMSG msg; // Message header info
-
- // Message attribute table
-
- static struct {
- dword attr; // Attribute bit
- char * psz; // Attribute name string
- char ch; // Command line option char or null if none
- } aMsgAttr[] = {
- MSGPRIVATE, "Pvt", 'P',
- MSGCRASH, "Crash", 'C',
- MSGREAD, "Recv", 0,
- MSGSENT, "Sent", 0,
- MSGFILE, "File", 'F',
- MSGFWD, "Transit", 0,
- MSGORPHAN, "Orphan", 0,
- MSGKILL, "Kill", 'K',
- MSGLOCAL, "Local", 0,
- MSGHOLD, "Hold", 'H',
- MSGXX2, "Rsvd2", 0,
- MSGFRQ, "Frq", 'Q',
- MSGRRQ, "Rrq", 'R',
- MSGCPT, "Cpt", 0,
- MSGARQ, "Arq", 'A',
- MSGURQ, "Urq", 'U',
- MSGSCANNED, "Scn", 'S',
- };
-
- /////////////////////////////////////////////////////////////////////////////
- // M i s c e l l a n e o u s s u b r o u t i n e s //
- /////////////////////////////////////////////////////////////////////////////
-
- /*
- * This subroutine displays logo
- */
-
- static void DoShowLogo(void)
- {
- fprintf(AUXTEXT,
- "\n"
- "Send Message Utility v"VERSION", "__DATE__", "__TIME__"\n"
- "Written by Pete Kvitek of JV Dialogue 1st BBS, 2:5020/6\n"
- "Copyright (C) 1991-1996 by JV Dialogue. All rights reserved.\n"
- "\n"
- );
- }
-
- /*
- * This subroutine displays help
- */
-
- static void DoShowHelp(void)
- {
- int iMsgAttr;
-
- fprintf(AUXTEXT,
- "Usage: SENDMSG <folder> <fromname,addr> [toname,addr] [-a<attr>] [-s<subj>]\n"
- "\n"
- " folder - specifies the mail folder path. If preceded\n"
- " with '$' then the folder is *.SQ? type base,\n"
- " otherwise it's assumed to be *.MSG style base\n"
- " name,addr - specifies message from/to name and address\n"
- " attr - specifies message attributes (P,H,F, etc..)\n"
- " subj - specifies message subject\n"
- "\n"
- "If any parameter includes spaces it should be enclosed in double quotas.\n"
- "The message body text file is supposed to be available through the standard\n"
- "input device. Use redirection or piping characters to set it in.\n"
- "\n"
- "Examples: SENDMSG c:\\mail Pete,2:5020/6 220/501 -aP \"-sNew Files\" < NEWFILE.LST\n"
- " echo Hi! | SENDMSG c:\\mail 2:5020/6 1.1 -aPF \"-sc:\\autoexec.bat\"\n"
- );
-
- // Show supported attributes
-
- fprintf(AUXTEXT, "\nAttibutes: ");
- for (iMsgAttr = 0; iMsgAttr < numbof(aMsgAttr); iMsgAttr++)
- if (aMsgAttr[iMsgAttr].ch)
- fprintf(AUXTEXT, "%c:%s ", aMsgAttr[iMsgAttr].ch,
- aMsgAttr[iMsgAttr].psz);
- fprintf(AUXTEXT, "\n");
- }
-
- /*
- * This sub routine builds a fully qualified path
- */
-
- BOOL BuildFullPath(char * pszDest, char * pszSrc)
- {
- #ifdef __MSC__
- // Build fill path using comiler service and check if ok
-
- if (_fullpath(pszDest, pszSrc, FN_MAXPATH) == NULL)
- return FALSE;
- #else
- char achDrive[FN_MAXDRIVE];
- char achDir[FN_MAXDIR];
- char achFile[FN_MAXFILE];
- char achExt[FN_MAXEXT];
- char achCurDir[FN_MAXDIR];
- int iCurDrive;
-
- // Decompose supplied path
-
- fnsplit(pszSrc, achDrive, achDir, achFile, achExt);
-
- // Preserve current drive
-
- iCurDrive = getdisk();
-
- // Check if drive specified in the supplied path and if not,
- // assume the current one
-
- if (!achDrive[0]) {
- strcpy(achDrive, "A:");
- achDrive[0]+= (char) iCurDrive;
- }
-
- // Set the current drive to the requested one and check if ok.
- // If failed, restore orginal drive and return error
-
- setdisk(toupper(achDrive[0]) - 'A');
- if (getdisk() != toupper(achDrive[0]) - 'A') {
- setdisk(iCurDrive);
- return FALSE;
- }
-
- // Preserve the current directory on the reqested drive and
- // check if ok, otherwise restore initial current drive and return
-
- strcpy (achCurDir, "\\");
- if (getcurdir(0, &achCurDir[1])) {
- setdisk(iCurDrive);
- return FALSE;
- }
-
- // Check if directory specified and make it current
-
- if (achDir[0]) {
-
- // Kill trailing back slash if it's not the only character
- // of the directory specification
-
- if ((achDir[strlen(achDir) - 1] == '\\') && (strlen(achDir) > 1 ))
- achDir[strlen(achDir) - 1] = '\0';
-
- // Change to the specified directory and check if ok. If failed,
- // restore the inital directory on the requested drive and change
- // to the initial drive
-
- if (chdir(achDir)) {
- chdir(achCurDir);
- setdisk(iCurDrive);
- return FALSE;
- }
- }
-
- // So we managed to make a requested directory current on the
- // requested drive. Now get its full specification and this
- // will be what we're after. If failed, just restore things back
-
- strcpy(achDir, "\\");
- if (getcurdir(0, &achDir[1])) {
- chdir(achCurDir);
- setdisk(iCurDrive);
- return FALSE;
- }
-
- // Compose the fully qualified file name and restore
- // the inital directory on the requested drive and change
- // to the initial drive
-
- fnmerge(pszDest, achDrive, achDir, achFile, achExt);
- chdir(achCurDir);
- setdisk(iCurDrive);
- #endif
-
- return TRUE;
- }
-
- /*
- * This routine scans in z:n/n.p address specification
- */
-
- static char * DoScanNetAddr(NETADDR * pnetAddr, char * psz)
- {
- char * pch, * pchEnd, * pchNext, ch;
-
- // Skip through the leading spaces and fix up the end
-
- for (pch = psz; isspace(*pch); pch++);
- for (pchNext = pch; *pchNext && !isspace(*pchNext); pchNext++);
- ch = *pchNext; *pchNext = '\0'; pchEnd = pch;
-
- // Scan in the zone if any
-
- if (*pch && !isspace(*pch) && strchr(pch, ':')) {
- while (isdigit(*pchEnd)) pchEnd++;
- if (*pchEnd != ':' || pch == pchEnd) return NULL;
- pnetAddr->zone = atoi(pch);
- pch = ++pchEnd;
- if (!isdigit(*pch) || !strchr(pch, '/')) return NULL;
- }
-
- // Scan in the net if any
-
- if (*pch && !isspace(*pch) && strchr(pch, '/')) {
- while (isdigit(*pchEnd)) pchEnd++;
- if (*pchEnd != '/' || pch == pchEnd) return NULL;
- pnetAddr->net = atoi(pch);
- pch = ++pchEnd;
- if (!isdigit(*pch)) return NULL;
- }
-
- // Scan in the node if any
-
- if (*pch && !isspace(*pch) && *pch != '.') {
- while (isdigit(*pchEnd)) pchEnd++;
- if (*pchEnd != '.' && !isspace(*pchEnd) && *pchEnd) return NULL;
- pnetAddr->node = atoi(pch);
- pch = pchEnd;
- }
-
- // Scan in the point if any
-
- if (*pch != '.') {
- if (!isspace(*pch) && *pch) return NULL;
- pnetAddr->point = 0;
- } else {
- for (pchEnd = ++pch; isdigit(*pchEnd); pchEnd++);
- if (!isspace(*pchEnd) && *pchEnd) return NULL;
- pnetAddr->point = atoi(pch);
- pch = pchEnd;
- }
-
- // Restore the zeroed trailing characters
-
- *pchNext = ch;
-
- // Check if zone or net is zero and return
-
- return (pnetAddr->zone && pnetAddr->net) ? pchNext : NULL;
- }
-
- /*
- * This subroutine scans name and network address
- */
-
- static BOOL DoScanNameAddr(char * psz, NETADDR * pnetAddr,
- char * pszName, short cchName)
- {
- char * pch;
- short cch;
-
- // Check if there is a name and scan it in
-
- if (isdigit(*psz))
- pch = psz;
- else
- if ((pch = strchr(psz, ',')) == NULL) {
- return FALSE;
- } else {
- cch = min((short)(pch - psz), cchName);
- memcpy(pszName, psz, cch);
- pszName[cch] = '\0';
- pch++;
- }
-
- // Scan in the network address if any
-
- DoScanNetAddr(pnetAddr, pch);
-
- return TRUE;
- }
-
- /*
- * This subroutine scans message attribute specification
- */
-
- static void DoScanMsgAttr(char * psz, dword * pattr)
- {
- short iAttr;
-
- // Scan through all the specified message attributes
-
- for (; *psz; psz++) {
- for (iAttr = 0; toupper(*psz) != aMsgAttr[iAttr].ch; iAttr++)
- if (iAttr >= numbof(aMsgAttr)) {
- fprintf(AUXTEXT, "Unknown message attribute: '%s'\n", psz);
- exit(EXIT_FAILURE);
- }
- *pattr|= aMsgAttr[iAttr].attr;
- }
- }
-
- /*
- * This subroutine prints out a message header
- */
-
- static void DoShowMsgHeader(XMSG * pmsg)
- {
- int iAttr;
- // Print out the message header
-
- fprintf(AUXTEXT,
- " To: %s, %u:%u/%u.%u\n"
- "From: %s, %u:%u/%u.%u\n"
- "Subj: %s\n",
- pmsg->to, pmsg->dest.zone, pmsg->dest.net, pmsg->dest.node, pmsg->dest.point,
- pmsg->from, pmsg->orig.zone, pmsg->orig.net, pmsg->orig.node, pmsg->orig.point,
- pmsg->subj
- );
-
- // Print out the message attribute if any
-
- if (pmsg->attr) {
- fprintf(AUXTEXT, "Attr:");
- for (iAttr = 0; iAttr < numbof(aMsgAttr); iAttr++)
- if (pmsg->attr & aMsgAttr[iAttr].attr)
- fprintf(AUXTEXT, " %s", aMsgAttr[iAttr].psz);
- putc('\n', AUXTEXT);
- }
- }
-
- /*
- * This subroutine to process the command line parameters
- */
-
- static void DoProcCmdLine(int cArg, char * apszArg[])
- {
- char * psz;
- short iArg = 1;
-
- // Display the logo screen and check if there are any
- // command line parameters specified and if not, display
- // help screen and quit now...
-
- DoShowLogo();
- if (cArg == 1) {
- DoShowHelp();
- exit(EXIT_FAILURE);
- }
-
- // Scan in the mail folder path specification and check if it's
- // a *.SQ? type database
-
- if (apszArg[iArg][0] == '$') {
- psz = &apszArg[iArg][1]; fsFlags|= FL_SQUISHMAIL;
- } else {
- psz = &apszArg[iArg][0];
- }
-
- // Build the fully qualified path and make it upper case
-
- if (!BuildFullPath(achPath, psz)) {
- fprintf(AUXTEXT, "Invalid mail folder path: '%s'\n", psz);
- exit(EXIT_FAILURE);
- } else {
- #ifndef __OS2__
- strupr(achPath);
- #endif
- iArg++;
- }
-
- // Scan in the 'From' name/address
-
- if (iArg >= cArg) {
- fprintf(AUXTEXT, "Missing 'From' address/name\n");
- exit(EXIT_FAILURE);
- } else
- if (!DoScanNameAddr(apszArg[iArg], &msg.orig, msg.from, lengof(msg.from)) ||
- msg.orig.zone == 0 || msg.orig.net == 0) {
- fprintf(AUXTEXT, "Invalid 'From' address: '%s'\n", apszArg[iArg]);
- exit(EXIT_FAILURE);
- } else {
- memcpy(&msg.dest, &msg.orig, sizeof(msg.dest));
- iArg++;
- }
-
- // Scan in the 'To' name/address if any
-
- if (iArg >= cArg || ISOPTION(apszArg[iArg][0])) {
- memcpy(&msg.dest, &msg.orig, sizeof(msg.dest));
- } else
- if (!DoScanNameAddr(apszArg[iArg], &msg.dest, msg.to, lengof(msg.to)) ||
- msg.dest.zone == 0 || msg.dest.net == 0) {
- fprintf(AUXTEXT, "Invalid 'To' address: '%s'\n", apszArg[iArg]);
- exit(EXIT_FAILURE);
- } else
- iArg++;
-
- // Process the command line options if any
-
- for (; iArg < cArg; iArg++)
- if (!ISOPTION(apszArg[iArg][0])) {
- fprintf(AUXTEXT, "Invalid option: '%s'\n", apszArg[iArg]);
- exit(EXIT_FAILURE);
- } else
- switch (tolower(apszArg[iArg][1])) {
- case 's': // Message subject
- strncpy(msg.subj, &apszArg[iArg][2], lengof(msg.subj));
- break;
- case 'a': // Message attributes
- DoScanMsgAttr(&apszArg[iArg][2], &msg.attr);
- break;
- default: fprintf(AUXTEXT, "Unknown option: '%s'\n", apszArg[iArg]);
- exit(EXIT_FAILURE);
- }
-
- // Set up default message header strings if not defined yet
-
- if (!msg.to[0]) strcpy(msg.to, msg.attr & MSGPRIVATE ? "SysOp" : "All");
- if (!msg.from[0]) strcpy(msg.from, "SysOp");
- if (!msg.subj[0]) strcpy(msg.subj, "<none>");
-
- // Explicitely set the 'Local' message attribute
-
- msg.attr|= MSGLOCAL;
- }
-
- /*
- * This subroutine returns an API error string
- */
-
- static char * DoGetApiError(void)
- {
- switch (msgapierr) {
- case MERR_NOMEM: return "not enough memory";
- case MERR_NOENT: return "area does not exist";
- case MERR_BADF: return "area is damaged";
- default: return "error unknown";
- }
- }
-
- /*
- * This subroutine opens a mail folder
- */
-
- static BOOL DoOpenMailFolder(void)
- {
- struct _minf minf;
-
- // Initialize the Scott's API and check if ok
-
- minf.req_version = 0;
- minf.def_zone = msg.orig.zone;
-
- if (MsgOpenApi(&minf) == -1) {
- fprintf(AUXTEXT, "MsgAPI initialization failed\n");
- exit(EXIT_FAILURE);
- }
-
- // Open the mail folder, lock it and check if ok
-
- if ((harea = MsgOpenArea( achPath
- , MSGAREA_NORMAL
- , fsFlags & FL_SQUISHMAIL ? MSGTYPE_SQUISH : MSGTYPE_SDM
- )) == NULL) {
- fprintf(AUXTEXT, "Can't open folder %s%s -- %s\n",
- achPath, fsFlags & FL_SQUISHMAIL ? ".SQ?" : "\\*.MSG",
- DoGetApiError());
- exit(EXIT_FAILURE);
- }
-
- return TRUE;
- }
-
- /*
- * This subroutine closes a mail folder
- */
-
- static BOOL DoCloseMailFolder(void)
- {
- // Check if opened
-
- if (harea == NULL)
- return FALSE;
-
- // Unlock and close the netmail folder and check if ok
-
- if (MsgCloseArea(harea) == -1) {
- fprintf(AUXTEXT, "Can't close mail folder: %s\n", DoGetApiError());
- exit(EXIT_FAILURE);
- }
-
- // Shut down the Scott's API
-
- if (MsgCloseApi() == -1) {
- fprintf(AUXTEXT, "MsgAPI shutdown failed\n");
- exit(EXIT_FAILURE);
- }
-
- return TRUE;
- }
-
- /*
- * This subroutine sets message creation date/stamp
- */
-
- static void DoSetMsgDateTime(XMSG * pmsg)
- {
- time_t sec;
- struct tm * ptime;
-
- // Get the current time
-
- sec = time(NULL); ptime = localtime(&sec);
-
- // Set message date time stamp
-
- pmsg->date_written.date.yr = ptime->tm_year - 80;
- pmsg->date_written.date.mo = ptime->tm_mon + 1;
- pmsg->date_written.date.da = ptime->tm_mday;
-
- pmsg->date_written.time.hh = ptime->tm_hour;
- pmsg->date_written.time.mm = ptime->tm_min;
- pmsg->date_written.time.ss = ptime->tm_sec / 2;
- }
-
- /*
- * This subroutine makes up a unique ^aMSGID stamp
- */
-
- static ULONG DoMakeMSGIDStamp(void)
- {
- static ULONG lStampPrev;
- ULONG lStamp, lSecs, lHund;
- unsigned iLoop = 0;
- #ifdef __OS2__
- static BOOL fInfoSeg = FALSE;
- static PGINFOSEG pgis;
- static PLINFOSEG plis;
- SEL selgis, sellis;
- #else
- union REGS regs;
- #endif
-
- // Under OS2 get pointers to the global and local info segments once
-
- #ifdef __OS2__
- if (!fInfoSeg) {
- DosGetInfoSeg(&selgis, &sellis);
- pgis = MAKEPGINFOSEG(selgis);
- plis = MAKEPLINFOSEG(sellis);
- fInfoSeg = TRUE;
- }
- #endif
-
- // Make up time stamp out of number of seconds since Jan 1, 1970
- // shifted 7 bits to the left OR'ed with current system clock and
- // loop untill we get a new stamp
-
- do {
- #ifdef __OS2__
- lSecs = (ULONG) pgis->time;
- lHund = (ULONG) pgis->hundredths;
- DosSleep(0);
- #else
- lSecs = (ULONG) time(NULL);
- regs.h.ah = 0x2c; intdos(®s, ®s);
- lHund = (ULONG) regs.h.dl;
- #endif
- lStamp = (lSecs << 7) | (lHund & 0x07f);
- } while ((lStampPrev >= lStamp) && (++iLoop < 0x7fff));
-
- // Check if we finally have unique ascending ^aMSGID kludge stamp
- // ATTN: What may be reasonable action here?
-
- if (lStampPrev >= lStamp) {
- fprintf(AUXTEXT, "Can't create unique ^aMSGID lStamp=%08lx, lStampPrev=%08lx\n\n\a",
- lStamp, lStampPrev);
- }
-
- return lStampPrev = lStamp;
- }
-
- /*
- * This subroutine creates a new message
- */
-
- static void DoCreateMessage(XMSG * pmsg)
- {
- long cchCtrl, cchBody;
- short cch, ich;
- char ach[512];
- char * pch;
- HMSG hmsg;
-
- // Get length of the message body. Note that the
- // tear line will not be written for the empty messages
-
- if ((cchBody = filelength(fileno(MSGTEXT))) > 0)
- cchBody+= sizeof(SMSG_TEARLINE);
- else
- cchBody = 0l;
-
- // Open the new message and check if ok
-
- if ((hmsg = MsgOpenMsg(harea, MOPEN_CREATE, 0)) == NULL) {
- fprintf(AUXTEXT, "Can't create message\n");
- exit(EXIT_FAILURE);
- }
-
- // Set the message creation date/time stamp
-
- DoSetMsgDateTime(pmsg);
-
- // Initizlize MSGID stamp generation logic so that we'll not get dupes
- // if running successively on fast machines
-
- DoMakeMSGIDStamp();
-
- // Create ^aMSGID kludge string
-
- sprintf(ach, "\x01""MSGID: %u:%u/%u.%u %08lx",
- pmsg->orig.zone, pmsg->orig.net,
- pmsg->orig.node, pmsg->orig.point,
- DoMakeMSGIDStamp());
-
- // Append PID kludge
-
- strcat(ach, SMSG_PID);
-
- // Calculate control info length including trailing zero
- // required by MsgWriteMsg api
-
- cchCtrl = strlen(ach) + 1;
-
- // Write out the new message header and check if ok
-
- if (MsgWriteMsg(hmsg, FALSE, pmsg, NULL, 0L, cchCtrl + cchBody,
- cchCtrl, ach) == -1) {
- fprintf(AUXTEXT, "Can't write message header or kludges\n");
- MsgCloseMsg(hmsg);
- exit(EXIT_FAILURE);
- }
-
- // Check if we have nothing to write into message body
-
- if (!cchBody) {
-
- // Write out the empty message body
-
- if (MsgWriteMsg(hmsg, TRUE, NULL, "", 1, 0L, 0L, NULL) == -1) {
- fprintf(AUXTEXT, "Can't write empty message body\n");
- MsgCloseMsg(hmsg);
- exit(EXIT_FAILURE);
- }
- } else {
-
- // Write out new message text if any. Replace all \n with \r
- // in order to conform FidoNet(tm) message body standards
-
- while ((cch = fread(ach, 1, sizeof(ach), MSGTEXT)) > 0) {
- for (pch = ach, ich = 0; ich < cch; pch++, ich++)
- if (*pch == '\n') *pch = '\r';
- if (MsgWriteMsg(hmsg, TRUE, NULL, ach, cch, 0L, 0L, NULL) == -1) {
- fprintf(AUXTEXT, "Can't write message body\n");
- MsgCloseMsg(hmsg);
- exit(EXIT_FAILURE);
- }
- }
-
- // Write out the tear line. Note that the trailing null is also
- // written since we're using 'sizeof()'
-
- if (MsgWriteMsg(hmsg, TRUE, NULL, SMSG_TEARLINE, sizeof(SMSG_TEARLINE),
- 0L, 0L, NULL) == -1) {
- fprintf(AUXTEXT, "Can't write tear line\n");
- MsgCloseMsg(hmsg);
- exit(EXIT_FAILURE);
- }
- }
-
- // Close the message just created and display the results
-
- MsgCloseMsg(hmsg);
-
- DoShowMsgHeader(&msg);
-
- fprintf(AUXTEXT, "Body: %lu byte(s)\n"
- "Mail: %s%s\n",
- cchBody, achPath,
- fsFlags & FL_SQUISHMAIL ? ".SQ?" : "\\*.MSG");
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // M a i n . . . //
- /////////////////////////////////////////////////////////////////////////////
-
- void main(int argc, char * argv[])
- {
- DoProcCmdLine(argc, argv);
- DoOpenMailFolder();
- DoCreateMessage(&msg);
- DoCloseMailFolder();
- exit(EXIT_SUCCESS);
- }
-
- /*
- * End of SENDMSG.C
- */
-